---
theme: gaia
_class: lead
paginate: true
backgroundColor: #fff
marp: true
---

<style>
img[alt~="center"] {
  display: block;
  margin: 0 auto;
}
code {
    background: #000;
}
pre {
    background: #000;
}
</style>

# Программирование на основе классов и шаблонов

<style scoped>
h1 {
    font-size: 1.5rem;
}
h2 {
    font-size: 1rem;
}
</style>

![bg left:40% 80%](../images/iu5edu_logo.jpg)

## Концепции и парадигмы программирования

**Аладин** Дмитрий Владимирович

[iu5edu.ru/wiki/cpp2](https://iu5edu.ru/wiki/cpp2)

---

## План

1. Понятия парадигма и концепция программирования.
2. Классификации парадигм.
3. Место парадигмы в разработке.
4. Императивная парадигма и ее виды.
5. Декларативная парадигма и ее виды.
6. Выполнение императивных и декларативных программ.
7. Объектно-ориентированная парадигма.

---

# Что такое "парадигма"?

<style scoped>
h1 {
    font-size: 1rem;
}
p {
    font-size: 0.7rem;
}
</style>

![bg left:40% 80%](./images/paradigms-mem.png)

**[Парадигма](https://dic.academic.ru/dic.nsf/business/9596)** (от греч. *paradeigma* - пример, образец; англ. *patadigm*) - исходная схема, модель, метод решения задачи, основополагающая теория.

**[Парадигма научная](https://dic.academic.ru/dic.nsf/enc_philosophy/902/ПАРАДИГМА)** - совокупность научных достижений, признаваемых всем научным сообществом в тот или иной период времени и служащих основой и образцом новых научных исследований.

**[Парадигма](https://github.com/Bandydan/php/blob/master/23_Object-class_this-inheritanse_incapsulation.md)** - совокупность подходов, идей, понятий, даже принципов, которые определяют, как писать код. Удобный синоним - *стиль*, хотя понятие парадигмы несколько шире.

*Какое же определение использовать?*

---

# А может это запрет на определённые действия внутри кода программы?

<style scoped>
h1 {
    font-size: 1rem;
}
p {
    font-size: 0.8rem;
}
</style>

![bg right:50% 95%](./images/uncle-bob-meme.png)

Это придумал [Роберт Мартин](https://ru.wikipedia.org/wiki/Мартин,_Роберт_(инженер)) — международный консультант в области разработки, известный среди разработчиков как *дядя Боб*.

[С его точки зрения](https://practicum.yandex.ru/blog/paradigmy-programmirovaniya/), **парадигмы** — это ограничения на определённые языковые конструкции, которые вынуждают использовать определённый стиль.

---

# "Золотое правило" определения

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 1rem;
}
</style>

![bg left:50% 95%](./images/gold-mem.jpg)

**Любое определение** – это, как правило, **открытое** определение, определение **принципиально неполное**, **предполагающее возможность дальнейшего изучения** явления с открытием всё новых и новых его свойств.

Больше про *проблему определения* [тут](https://textarchive.ru/c-1170568-p2.html).

---

# А что такое "концепция"?

<style scoped>
h1 {
    font-size: 1rem;
}
p {
    font-size: 0.8rem;
}
li {
    font-size: 0.8rem;
}
</style>

Из фонда "золотых цитат":

> Когда речь о защите [диссертации], то надо использовать термины так, как принято в Совете, где намечается защита.

В качестве примера, можно привести такую [группу определений](https://sciencing.com/differences-between-concepts-theories-paradigms-8415723.html):

- **Концепция** - это термин, который широко используется в повседневном английском языке для обозначения **идеи**.
- **Теория** - это устоявшийся **научный принцип**, который подтверждается убедительными экспериментальными и наблюдательными данными.
- **Парадигма** - это центральная концептуальная основа того, как вы можете **видеть** окружающий мир.

---

# Я настоятельно прошу рекрутеров указать, кто из них покемон...

<style scoped>
h1 {
    font-size: 0.9rem;
}
p {
    font-size: 0.7rem;
}
</style>

![bg left:60% 95%](./images/pokemon-mem.jpg)

Зачастую **парадигма** или **парадигмы**, которые использует программист, определяются языком, проектом и существующим кодом на этом проекте, парадигмой, которой придерживается компания или конкретная команда проекта.

*P.S.* Откуда мем узнать [тут](https://wiert.me/2018/12/19/i-tyically-ask-recruiters-to-point-out-which-of-these-are-pokemon-via-my-linkedin-profile-programmerhumor/).

---

# Когда одной парадигмы не хватает...

<style scoped>
h1 {
    font-size: 1.5rem;
}
</style>

Многие языки программирования являются **мультипарадигменными**, т.е. поддерживают не одну, а несколько популярных парадигм, т.е. позволяют писать в разных парадигмах-стилях.

В различных источниках можно встретить множество названий парадигм, **различные**, и иногда **даже противоречащие** друг другу **системы классификаций** этих парадигм.

*Чувствуете подвох с классификациями?*

---

# "Золотое правило" классификации

<style scoped>
h1 {
    font-size: 1.7rem;
}
</style>

**Любая классификация всегда относительна.**

Один и тот же объект может быть классифицирован по разным признакам или критериям. Часто встречаются ситуации, когда в зависимости от условий внешней среды объект может быть отнесен к разным классификационным группировкам.

Больше про классификацию информации [здесь](https://life-prog.ru/2_79235_klassifikatsiya-informatsii-po-raznim-priznakam.html).

---

# Парадигмы с точки зрения истории

<style scoped>
h1 {
    font-size: 1.1rem;
}
p {
    font-size: 0.8rem;
}
li {
    font-size: 0.8rem;
}
</style>

![bg left:30% 70%](images/timeline-of-programming-languages.jpg)

1. Императивная
2. Структурная
3. Модульная
4. Объектно ориентированная
5. Декларативная
6. Функциональная
7. Реактивная
8. и многие многие другие менее известные...

← Появление определенной парадигмы тесно связано с появлением определенного языка программирования.

---

# Парадигмы с точки зрения относительного развития

<style scoped>
h1 {
    font-size: 1rem;
}
</style>

![bg 70%](images/paradigms-programming.jpeg)

---

# Парадигмы с точки зрения... #$%?!

<style scoped>
h1 {
    font-size: 0.8rem;
}
p {
    font-size: 0.8rem;
}
</style>

![bg left:70% 100%](images/principal-programming-paradigms.png)

Одна и та же задача может быть [решена по-разному](https://practicum.yandex.ru/blog/paradigmy-programmirovaniya/): **каждая парадигма подразумевает своё решение**!

---

# Почему такой зоопарк из парадигм?

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.9rem;
}
li {
    font-size: 0.9rem;
}
</style>

Посмотрим на некоторые критерии качества программ:

– результативность;
– надежность;
– устойчивость;
– автоматизируемость;
– эффективное использование ресурсов (время, память, устройства,
информация, люди);
– удобство разработки и применения;
– наглядность текста программы;
– наблюдаемость процесса работы программы;
– диагностика происходящего.

---

# От чего зависит достижение критериев качества программы?

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.9rem;
}
</style>

Вспомним опять про то, что **одна и та же задача может быть решена по-разному**. Достижение некоторого критерия качества также является задачей!

Порядок критериев нередко претерпевает изменения по мере развития области применения программы, роста квалификации пользователей, модернизации оборудования, информационных технологий и программотехники.

*P.S.* Некоторые парадигмы программирования не появились бы, если не происходило совершенствование ЭВМ.

---

# При решении задачи мы сталкиваемся с ограничениями!

<style scoped>
h1 {
    font-size: 1rem;
}
p {
    font-size: 0.75rem;
}
li {
    font-size: 0.75rem;
}
</style>

Непрерывное развитие пространства, в котором решается задача, вводит дополнительные требования к **стилю программирования** информационных систем:

– гибкость;
– модифицируемость;
– верифицируемость;
– безопасность;
– мобильность/переносимость;
– адаптируемость;
– конструктивность;
– измеримость характеристик и качества;
– улучшаемость.

*P.S.* А что Дядя Боб говорил про парадигмы? А какие еще определения у парадигм?

---

# Место парадигмы в разработке

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.8rem;
}
</style>

Парадигма выбирается, исходя из архитектуры системы и влияет на построение и реализацию ее компонентов. [Роль парадигм программирования](https://lectures.ostrov.ski/02-development/10-paradigms-1/) в разработке ПО:

![height:400px center](images/place-paradigm-in-development.png)

---

# Императивная парадигма и ее виды

<style scoped>
h1 {
    font-size: 1.5rem;
}
p {
    font-size: 1rem;
}
li {
    font-size: 1rem;
}
</style>

**Императивная парадигма программирования** - это стиль написания кода, подразумевающий *подробное описание алгоритма* решения задачи и *получения искомых данных*.

В императивном стиле:

1. **Описывают** алгоритм решения поставленной задачи.
2. **Сохраняют** состояния в переменных.
3. Зачастую **снабжают** код комментариями, поскольку по самому коду бывает сложно понять его итоговую цель.

---

# Вопрос: КАК?

Императивный стиль использует **много переменных** в процессе своей работы и часто **сохраняет** в них **промежуточные результаты** вычислений.

Эта парадигма популярна потому, что она в точности соответствует тому, как работает компьютер: **последовательно выполняет инструкции** и **использует память для хранения промежуточных результатов**.

Обычно говорят, что императивная программа отвечает на вопрос **КАК** ("как достичь нужного результата").

---

# История императивных парадигм

<style scoped>
h1 {
    font-size: 0.9rem;
}
h2 {
    font-size: 0.75rem;
}
p {
    font-size: 0.75rem;
}
</style>

![bg left:45% 95%](images/machineneumann.gif)

В соответствии с существовавшей в 1940-х годах архитектурой ЭВМ (архитектура фон Неймана) в программировании использовался процедурных подход, **процедурная парадигма программирвания**.

## [Архитектура фон Неймана (принстонская архитектура)](https://inf1.info/machineneumann)

— принцип совместного хранения команд и данных в памяти компьютера.

Альтернативой архитектуре фон Неймана ("принстонской архитектуре") является [гарвардская архитектура](https://digteh.ru/dsp/garvard/).

---

# Процедурная парадигма

**Процедурная парадигма** подразумевает **написание алгоритмов** программ пошагово и **частое использование подпрограмм**, называемых процедурами

**Процедуры** - практически синонимы функций. Единственная разница их в том, что процедуры просто выполняют какие-то действия, ничего не возвращая, а функции могут и должны возвращать значения.

---

# Историческая справка по холиварам

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.75rem;
}
</style>

Процедурная парадигма допускает использование оператора `goto`, достоинства которого уже к шестидесятым годам представлялись спорными. В 1968 году Эдсгер Дейкстра пишет известную статью ["О вреде оператора goto"](https://inf.1sept.ru/view_article.php?ID=200800105), дебаты усиливаются, и к 1970-м годам формулируют новую парадигму - **структурную**.

![height:400px center](images/goto-mem.png)

---

# Структурная парадигма

Структурная парадигма программирования запрещает использование оператора `goto`, настоятельно рекомендуя использовать другие подходы:

1. **последовательность** (выполнение программы *сверху вниз*),
2. **ветвление** (при помощи *условий*);
3. **цикличность** (при помощи операторов *циклов*).

В то же самое время развивалась **модульная парадигма**.

---

# Модульная парадигма

<style scoped>
h1 {
    font-size: 1.5rem;
}
p {
    font-size: 0.9rem;
}
</style>

**Модульное парадигма** — это организация программы как совокупности небольших независимых блоков, называемых модулями, структура и поведение которых подчиняются определённым правилам.

По модульной парадигме, необходимо размещать самодостаточный код в отдельные модули (чаще всего, отдельные файлы), которые могут взаимодействовать между собой.

*P.S.* Обсуждение объектно-ориентированной парадигмы пока пропустим.

---

# Декларативная парадигма и ее виды

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.8rem;
}
li {
    font-size: 0.8rem;
}
</style>

Декларативная парадигма программирования представляет собой стиль описания того, **что** вы хотите увидеть в итоге (ответ на вопрос ЧТО).

В декларативном стиле:

1. **не пишут**, как решить задачу, но пишут, что требуется получить;
2. **не сохраняют** промежуточные состояния;
3. **пишут** так, чтобы по виду кода можно было понять его цель.

К декларативным парадигмам часто относят:

- **функциональную**;
- **логическую**.

---

# Функциональная парадигма

**Функциональное парадигма** — это парадигма декларативного программирования, в которой программы создаются путем последовательного применения функций, а не инструкций.

Каждая из этих функций принимает **входное** значение и возвращает согласующееся с ним **выходное** значение, **не изменяясь** и **не подвергаясь** воздействию со стороны состояния программы.

---

# Чистые функции

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.8rem;
}
li {
    font-size: 0.8rem;
}
</style>

Чистые функции не производят побочных эффектов и не зависят от глобальных переменных или состояний.

![height:350px center](images/pure-functions.png)

*P.S.* Это в теории. На деле языки функциональные языки делятся на чистые (Haskell) и с побочными эффектами (большинство языков).

---

# Функциональная парадигма сложнее, чем кажется на первый взгляд...

<style scoped>
h1 {
    font-size: 1rem;
}
p {
    font-size: 0.75rem;
}
li {
    font-size: 0.75rem;
}
</style>

Есть ряд определений, которые делают функциональное программирование отдельной парадигмой и стилем создания алгоритмов:

- Функция или идентифицированный блок кода;
- Чистые функции;
- Лямбда функции;
- Функции высшего порядка;
- Композитные функции;
- Константы;
- Замыкания;
- Рекурсия.

Боле подробно [здесь](https://itstan.ru/programmirovanie/chto-takoe-funktsionalnoe-programmirovanie.html).

---

# Логическая парадигма

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.8rem;
}
li {
    font-size: 0.8rem;
}
</style>

![bg right:45% 95%](images/logic-programming-mem.png)

**Логическое программирование** - это парадигма программирования, которая в значительной степени основана на формальной логике.

Любая программа, написанная на языке логического программирования, представляет собой **набор предложений** в логической форме, выражающих **факты** и **правила** о некоторой проблемной области.

---

# Виды логического вывода

<style scoped>
h1 {
    font-size: 1.5rem;
}
h2 {
    font-size: 1.2rem;
}
p {
    font-size: 0.8rem;
}
</style>

## Прямой логический вывод

Программа записывается в виде продукционных правил `ЕСЛИ условие, ТО действие`. Порядок вызова правил определяется динамически машиной вывода.

Результат выполнения предыдущих правил меняет состояние машины вывода (операционную память) и приводит к вызову следующих правил. Цель динамически выводится в результате выполнения правил.

## Обратный логический вывод

От цели к данным.

---

# Как выполняется программа, использующая определенную парадигму?

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.8rem;
}
</style>

Давайте посмотрим как выполняются императивные и декларативные программы. Для этого воспользуемся материалом, который расположен [здесь](https://lectures.ostrov.ski/02-development/10-paradigms-1/).

![height:350px center](images/varan.jpg)

---

# Выполнение императивной программы

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.8rem;
}
</style>

Императивная программа использует именованные области памяти (переменные) для хранения состояния вычислений.

![height:300px center](images/imperative-program.png)

---

# Выполнение декларативной программы

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.8rem;
}
</style>

Декларативная программа не взаимодействует напрямую с памятью, поручая эту работу интерпретатору.

![height:380px center](images/declarative-program.png)

*P.S.* Вопрос: а кто написал инструкции для интерпретатора?)

---

# Сколько парадигм поддерживает Python?

<style scoped>
h1 {
    font-size: 1rem;
}
</style>

![bg 90%](images/python-paradigms-mem.jpg)

---

# Ответ: [много](https://pin.it/2KZtquG) 🤷

<style scoped>
h1 {
    font-size: 1.2rem;
}
li {
    font-size: 0.9rem;
}
</style>

![bg left:60% 95%](./images/how-much-python-mem.jpg)

Python поддерживает:

1. структурное;
2. объектно-ориентированное;
3. функциональное;
4. императивное;
5. аспектно-ориентированное;
6. и другие...

---

# А как дела у других?

<style scoped>
h1 {
    font-size: 1rem;
}
</style>

![bg 90%](images/programming-languages.png)

---

# А мы про слона не забыли (ООП)?

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.9rem;
}
</style>

![height:400px center](images/elephant-mem.jpg)

Самое время вернуться к [статье](http://artlib.osu.ru/Docs/piter/bookchap/978594723842.html), которая упоминалась при обсуждении организации декомпозиции программы!

---

# Появление ООП — реакция на кризис программного обеспечения

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.8rem;
}
</style>

![height:400px center](images/crisis-mem.jpg)

*Как вы думаете, что произошло такого, что пришлось придумывать ООП?*

---

# Разработчики перестали вывозить

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.8rem;
}
</style>

![bg left:50% 95%](./images/this-is-fine.png)

Методы структурного программирования уже не позволяли справляться с **растущей сложностью промышленного программного продукта (системы)**.

Следствия — срыв сроков проектов, перерасход бюджета, урезанная функциональность и множество ошибок.

---

# И где искать решение?

<style scoped>
h1 {
    font-size: 1.5rem;
}
p {
    font-size: 1rem;
}
</style>

Способ управления сложными системами был известен еще в древности — *divide et impera* ([разделяй и властвуй](https://www.pravmir.ru/razdelyay-i-vlastvuy-kto-skazal-eto/)). То есть выход — в **декомпозиции** системы на все меньшие и меньшие подсистемы, каждую из которых можно совершенствовать независимо.

> Святой Бруно сам не шевельнет и пальцем, чтобы опровергнуть обоих своих противников, он знает более удобный способ избавиться от них, он предоставляет их — divide et impera — их собственной распре
> [Карл Маркс](https://sharlib.com/read_329940-24)

---

# Критерии качества декомпозиции проекта

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 1rem;
}
li {
    font-size: 1rem;
}
</style>

Для оценки качества программного проекта нужно учитывать, кроме всех прочих, следующие два показателя:

- **Сцепление** (*cohesion*) внутри компонента — показатель, характеризующий степень взаимосвязи отдельных его частей.
- **Связанность** (*coupling*) между компонентами — показатель, описывающий интерфейс между компонентом-клиентом и компонентом-сервером. Общее число входов и выходов сервера есть мера связанности. Чем меньше связанность между двумя компонентами, тем проще понять и отслеживать в будущем их взаимодействие.

---

# Что принесло с собой ООП?

<style scoped>
h1 {
    font-size: 1.2rem;
}
p {
    font-size: 0.8rem;
}
li {
    font-size: 0.8rem;
}
</style>

[Четыре основных принципа](https://learn.microsoft.com/ru-ru/dotnet/csharp/fundamentals/tutorials/oop) объектно-ориентированного программирования следующие:

- **Абстракция**. Моделирование требуемых атрибутов и взаимодействий сущностей в виде классов для определения абстрактного представления системы.
- **Инкапсуляция**. Скрытие внутреннего состояния и функций объекта и предоставление доступа только через открытый набор функций.
- **Наследование**. Возможность создания новых абстракций на основе существующих.
- **Полиморфизм**. Возможность реализации наследуемых свойств или методов отличающимися способами в рамках множества абстракций.

---

<style scoped>
p {
    font-size: 1.5rem;
    color: white;
}
</style>

**Это мир после
появления ООП**

![bg](./images/after-oop.jpg)

---

# Вопросы?

<style scoped>
p {
  text-align: center;
}
</style>

![questions height:500px](../images/questions.jpg)
